/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

//===========================================================================================
#include <time.h>
#include <crtdbg.h>

//===========================================================================================
#include <dylab/utils/log/Log.h>

//===========================================================================================
dylab::Log::CallTracker::CallTracker(const String & _function, const String & _file, uint32_t _line)
: mFunction(_function)
{ 	
	Log::ScopedExLock exla(Log::getSingleton());
	exla->log(String::fmt(">>> %1% (%2%:%3%):", mFunction, _file, _line));
    exla->indent();
}
//-----------------------------------------------------------------------------
dylab::Log::CallTracker::~CallTracker()
{ 
	Log::ScopedExLock exla(Log::getSingleton());
	exla->log(String::fmt("<<< %1%", mFunction));
    exla->unindent();
}
//-----------------------------------------------------------------------------
dylab::Log::ObjectTracker::ObjectTracker(void * _instance, const String & _class, const String & _file)
: mObject(_instance)
{ 
    DYLAB_LOGF3("CTOR: %1%.%2% (%3%):", _class, _instance, _file);
}
//-----------------------------------------------------------------------------
dylab::Log::ObjectTracker::~ObjectTracker()
{ 
    DYLAB_LOGF("DTOR: %1%", mObject);
}

//===========================================================================================
dylab::Log::Log()
: mIndentDepth(0)
{
    //TODO: move to more appropriate place?
#   if defined(DYLAB_PLATFORM_WINDOWS)
        _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_CRT_DF);
#   endif
}
//-----------------------------------------------------------------------------
dylab::Log::~Log()
{
}
//-----------------------------------------------------------------------------
void dylab::Log::registerListener(const String & _name, IListener * _listener)
{
	// check the pointer argument
	DYLAB_ASSERT(_listener != NULL);

	// insert the listener to the container
	mLogListeners.insert(_name, _listener);
}
//-----------------------------------------------------------------------------
dylab::Log::IListener * 
dylab::Log::unregisterListener(const String & _name)
{
	// return the pointer to the listener removed from the container
	return mLogListeners.remove(_name);
}
//-----------------------------------------------------------------------------
void dylab::Log::log(const String & message)
{ 
	// log the message
    _log(message); 
}
//-----------------------------------------------------------------------------
void dylab::Log::_log(const String & message)
{ 
    char timestr[32]; 
    __time64_t ltime; 
	struct tm ltm;
    
    // format local time
    _time64(&ltime);
	if (_localtime64_s(&ltm, &ltime))
		strcpy_s(timestr, "???: ");
	else		
		strftime(timestr, sizeof(timestr), "%H:%M:%S: ", &ltm);

    // create indentaition String
    String indent = "";
    for (uint32_t i = 0; i < mIndentDepth; i++)
        indent += ".";

    // add formated callstack entries    
    String s = timestr + indent + message;

    // pass it to all registered log listeners
    for (Listeners::Iterator listener(mLogListeners); listener.isValid(); listener++)
        listener->logMessage(s);
}
//-----------------------------------------------------------------------------
void dylab::Log::indent()
{
    //TODO: one for each thread
    mIndentDepth++;
}
//-----------------------------------------------------------------------------
void dylab::Log::unindent()
{
    //TODO: one for each thread
    mIndentDepth--;
}
//-----------------------------------------------------------------------------